package local.sumw3.findmydevices.object;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;

import local.sumw3.findmydevices.object.bean.Device;
import local.sumw3.findmydevices.object.bean.User;
import local.sumw3.findmydevices.object.utils.Base64;
import local.sumw3.json.JSONException;
import local.sumw3.json.JSONObject;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;

/**
 * A java client for Apple's Find My iPhone service. This allows you to
 * programmatically retrieve your devices's current location and push messages
 * (and an optional alarm) to the remote device.
 * 
 * Migrated from Sosumi project at https://github.com/tylerhall/sosumi.
 * 
 * Under license of The MIT License.
 * 
 * @author sumw3
 * 
 */

public class FindMyDevices {

    private String userName_ = null;

    private String userPassword_ = null;

    private String partition_ = null;

    private List<Device> deviceList_ = null;

    private User user_ = null;

    private String oriResText_ = null;

    public FindMyDevices(String userName, String userPassword) throws IOException {
        userName_ = userName;
        userPassword_ = userPassword;
        initPartition();
    }

    private HttpResponse postReqeust(String url, String body) throws IOException {
        HttpResponse response = null;
        if (partition_ == null) {
            url = "https://fmipmobile.icloud.com" + url;
        } else {
            url = "https://" + partition_ + url;
        }
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Content-type", "application/json; charset=utf-8");
        httpPost.setHeader("X-Apple-Find-Api-Ver", "2.0");
        httpPost.setHeader("X-Apple-Authscheme", "UserIdGuest");
        httpPost.setHeader("X-Apple-Realm-Support", "1.0");
        httpPost.setHeader("User-agent", "Find iPhone/1.2 MeKit (iPad: iPhone OS/4.2.1)");
        httpPost.setHeader("X-Client-Name", "iPad");
        httpPost.setHeader("X-Client-UUID", "0cf3dc501ff812adb0b202baed4f37274b210853");
        httpPost.setHeader("Accept-Language", "en-us");
        httpPost.setHeader("Connection", "keep-alive");
        httpPost.setHeader("Authorization",
                "Basic " + Base64.encode((userName_ + ":" + userPassword_).getBytes("UTF-8")));

        StringEntity reqEntity = new StringEntity(body, "UTF-8");
        httpPost.setEntity(reqEntity);
        response = httpClient.execute(httpPost);
        return response;
    }

    private void initPartition() throws IOException {
        HttpResponse res = postReqeust(String.format(CommonConstants.QUERY_URL, userName_),
                CommonConstants.QUERY_JSON_BODY);
        Header[] headers = res.getHeaders("X-Apple-MMe-Host");
        if (headers != null && headers.length > 0) {
            partition_ = headers[0].getValue();
        }
    }

    public void updateDevice() throws JSONException, IllegalStateException, IOException {
        HttpResponse res = postReqeust(String.format(CommonConstants.QUERY_URL, userName_),
                CommonConstants.QUERY_JSON_BODY);
        oriResText_ = inputStream2String(res.getEntity().getContent());
        if (oriResText_ != null && !"".equals(oriResText_)) {
            if(oriResText_.trim().equals(CommonConstants.ERROR_RESPONSE.trim())){
                throw new IllegalArgumentException(CommonConstants.ERRORMSG_WRONGACESS);
            }
            JSONObject jsonBody = new JSONObject(oriResText_);
            deviceList_ = Device.parseFromJSON(jsonBody);
            user_ = User.parseFromJSON(jsonBody);
        }
    }

    public void sendMsg(boolean isAlarm, String subject, String text) throws IllegalStateException, JSONException,
            IOException {
        updateDevice();
        if (deviceList_ != null) {
            Device device = deviceList_.get(0);
            sendMsg(device.getId(), isAlarm, subject, text);
        }
    }

    public void sendMsg(String deviceID, boolean isAlarm, String subject, String text) throws JSONException,
            IOException {
        postReqeust(String.format(CommonConstants.SENDMSG_URL, userName_),
                String.format(CommonConstants.SENDMSG_JSON_BODY, deviceID, isAlarm, subject, text));
    }

    public List<Device> getDeviceInfo() {
        return deviceList_;
    }

    public User getUserInfo() {
        return user_;
    }

    public String getResponseText() {
        return oriResText_;
    }

    private String inputStream2String(InputStream is) throws IOException {
        try {
            BufferedReader in = new BufferedReader(new InputStreamReader(is));
            StringBuffer buffer = new StringBuffer();
            String line = "";
            while ((line = in.readLine()) != null) {
                buffer.append(line);
            }
            return buffer.toString();
        } finally {
            is.close();
        }
    }
}
